package edu.gatech.bsbmule.model;

import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;

import edu.gatech.bsbmule.presenter.MapScreenPresenter;
import edu.gatech.bsbmule.util.StatisticsManager;
import edu.gatech.bsbmule.util.StatisticsRecord;
import edu.gatech.bsbmule.view.EndOfGameScreen;
import edu.gatech.bsbmule.view.MainWindow;
import edu.gatech.bsbmule.view.TownWindow;
/**
 * Customized wrapper for Java built-in Timer with other functionalities
 * 
 * @author BSB
 * @version 1.0 10/29/2013
 */
public class CustomizedTimer extends Timer {
	
	private Game game;
	private MapScreenPresenter msp;
	
	private Timer timer;
	private EndOfTimeTask task;
	
	private long startingTime;

	private static CustomizedTimer instance = null;
	
	public static CustomizedTimer getInstance() {
		if (instance == null) {
			instance = new CustomizedTimer();
		}
		return instance;
	}
	
	/**
	 * Constructor
	 */
	private CustomizedTimer() {
		timer = new Timer();
		task = new EndOfTimeTask();
		game = Game.getInstance();
	}
	
	/**
	 * Map screen presenter
	 * 
	 * @param MapScreenPresenter msp
	 */
	public void setMapScreenPresenter(MapScreenPresenter msp) {
		this.msp = msp;
	}
	
	/**
	 * Start the timer
	 */
	public void start() {
		// Prints the current round and player name
		msp.log("[Round " + game.getCurrentRound() + " for " + game.getCurrentPlayer().getName() + "...]\n");
		
		// Setup the starting time for use of pause/resume
		startingTime = System.currentTimeMillis();
		
		// Schedule a new task which reads/updates from periods in Game recursively call schedule() itself
		timer.schedule(task, game.getPeriod(1, 0));
		
	}
	
	/**
	 * Store remaining time
	 */
	public void updateRemainingTime() {
		// Cancel the current Timer and make a new one
		timer.cancel();
		timer = new Timer();
		
		// Replace the existing period with the current remaining time
		game.updatePeriod(game.getCurrentRound() - 1, game.getPlayerCount(), getRemainingTime());
		msp.log("[Game paused]");
	}
	
	/**
	 * Gives back how much time is left according to current time and scheduled time
	 * @return remaining time 
	 */
	public long getRemainingTime() {
		long timeElapsed = System.currentTimeMillis() - startingTime;
		long timeRemaining = game.getPeriod(game.getCurrentRound() - 1, game.getPlayerCount()) - timeElapsed;
		return timeRemaining;
	}
	
	/**
	 * By pass the current player and goes to the next
	 */
	public void byPass() {
		// Cancel the current Timer and make a new one
		timer.cancel();
		timer = new Timer();
		
		nextOperations();
	}
	
	/**
	 * What happens after one player's turn has ended
	 * 
	 * @author BSB
	 * @version 1.0 10/26/2013
	 * 
	 */
	private class EndOfTimeTask extends TimerTask {
		@Override
		public void run() {
			nextOperations();
		}
	}
	
	/**
	 * Define what operations to perform after a player's turn is end
	 */
	private void nextOperations() {
		
		// If all players end
		if (game.isEndOfTheGame())
		{
			timer.cancel();
			msp.log("[All players end!]");
			MainWindow.getInstance().setPanel(EndOfGameScreen.getInstance());
			MainWindow.getInstance().setPauseItemEnable(false);
			MainWindow.getInstance().setSaveItemEnable(false);
		}
		
		// Else the game is not end
		else
		{
			// Print out what this player has got
			msp.log("[End of round "
				+ game.getCurrentRound() + " for "
				+ game.getCurrentPlayer().getName()
				+ "]\n[Round lasted for " + (int)(game.getPeriod(game.getCurrentRound() - 1, game.getPlayerCount()) / 1000)
				+ " seconds]\n[Player info]\n"
				+ game.getCurrentPlayer()
				+ "\n");
			
			// Create record and add to statistics
			Player currentPlayer = game.getCurrentPlayer();
			StatisticsRecord record = StatisticsRecord.buildRecord()
					.setMoney(currentPlayer.getMoney())
					.setTiles(currentPlayer.getTiles().size())
					.setFood(currentPlayer.getFood())
					.setEnergy(currentPlayer.getEnergy())
					.setScore(currentPlayer.getScore());
			StatisticsManager.getInstance().putRecord(game.getCurrentRound(), currentPlayer.getName(), record);			
						
			// If it is not last round, change next round remaining time
			// This is to avoid IndexOutOfBound
			if (!game.isLastRound()) {
				
				// Computes the remaining time for next round for this player
				long nextRemainingTime = game.getNextRemainingTime();
				
				// Updates the time interval for next round for this player 
				game.updatePeriod(game.getCurrentRound(), game.getPlayerCount(), nextRemainingTime);
			}
			
			// Go to the next player
			game.nextPlayer();
			TownWindow.getInstance().dispose();
			
			// Adds all the resources the player produces to the player
			game.getCurrentPlayer().production();
			
			if (!game.getCurrentPlayer().equals(game.getLoser())){
				int randomEvent = Game.getInstance().getRandomEvent(); 
				if (randomEvent != Game.NORANDOMEVENT){
					Game.getInstance().randomEvent(randomEvent);
					
					msp.log("[Random event happened!]");
					String randomEventText = "";
					
					if (randomEvent == Game.RANDOMEVENT_1){
						randomEventText = "YOU JUST RECEIVED A PACKAGE FROM THE " 
								+ "GT ALUMNI CONTAINING 3 FOOD AND 2 ENERGY UNITS.";
					}
					else if (randomEvent == Game.RANDOMEVENT_2){
						randomEventText = "A WANDERING TECH STUDENT REPAID " 
								+ "YOUR HOSPITALITY BY LEAVING TWO BARS OF ORE.";
					}
					else if (randomEvent == Game.RANDOMEVENT_3){
						randomEventText = "THE MUSEUM BOUGHT YOUR ANTIQUE PERSONAL COMPUTER "
								+ "FOR $" + 8 * Game.getInstance().returnMultiplier();
					}
					else if (randomEvent == Game.RANDOMEVENT_4){
						randomEventText = "YOU FOUND A DEAD MOOSE RAT AND SOLD THE HIDE " 
								+ "FOR $" + 2 * Game.getInstance().returnMultiplier();
					}
					else if (randomEvent == Game.RANDOMEVENT_5){
						randomEventText = "FLYING CAT-BUGS ATE THE ROOF "
								+ "OFF YOUR HOUSE. REPAIRS COST $" 
								+ 4 * Game.getInstance().returnMultiplier(); 
					}
					else if (randomEvent == Game.RANDOMEVENT_6){
						randomEventText = "MISCHIEVOUS UGA STUDENTS BROKE INTO YOUR " 
								+ "STORAGE SHED AND STOLE HALF YOUR FOOD."; 
					}
					else if (randomEvent == Game.RANDOMEVENT_7){
						randomEventText = "YOUR SPACE GYPSY INLAWS MADE A MESS OF THE " 
								+ "TOWN. IT COST YOU $"
								+ 6 * Game.getInstance().returnMultiplier() 
								+ " TO CLEAN IT UP."; 
					}
					msp.log(randomEventText); 
				}
			}

			
			// Another round for next player
			msp.log("[Round " + game.getCurrentRound()
					+ " for " + game.getCurrentPlayer().getName() + "...]");
			msp.updatePlayerInfo(game.getCurrentPlayer());
			msp.setTurnStatus(game.getCurrentRound());
			
			// Reset the current time
			startingTime = System.currentTimeMillis();
			
			// Recursively calls the schedule method
			if (!game.isEndOfTheGame())
			{
				timer.schedule(new EndOfTimeTask(), game.getPeriod(game.getCurrentRound() - 1, game.getPlayerCount()));
			}
		}
	
	}
}
